// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef NIM_CPP_WRAPPER_UTIL_JSON_ALLOCATOR_H_INCLUDED
#define NIM_CPP_WRAPPER_UTIL_JSON_ALLOCATOR_H_INCLUDED

#include <cstring>
#include <memory>

#pragma pack(push, 8)

namespace nim_cpp_wrapper_util {
namespace Json {
template <typename T>
class SecureAllocator {
public:
    // Type definitions
    using value_type = T;
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    /**
     * Allocate memory for N items using the standard allocator.
     */
    pointer allocate(size_type n) {
        // allocate using "global operator new"
        return static_cast<pointer>(::operator new(n * sizeof(T)));
    }

    /**
     * Release memory which was allocated for N items at pointer P.
     *
     * The memory block is filled with zeroes before being released.
     * The pointer argument is tagged as "volatile" to prevent the
     * compiler optimizing out this critical step.
     */
    void deallocate(volatile pointer p, size_type n) {
        std::memset(p, 0, n * sizeof(T));
        // free using "global operator delete"
        ::operator delete(p);
    }

    /**
     * Construct an item in-place at pointer P.
     */
    template <typename... Args>
    void construct(pointer p, Args&&... args) {
        // construct using "placement new" and "perfect forwarding"
        ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
    }

    size_type max_size() const { return size_t(-1) / sizeof(T); }

    pointer address(reference x) const { return std::addressof(x); }

    const_pointer address(const_reference x) const { return std::addressof(x); }

    /**
     * Destroy an item in-place at pointer P.
     */
    void destroy(pointer p) {
        // destroy using "explicit destructor"
        p->~T();
    }

    // Boilerplate
    SecureAllocator() {}
    template <typename U>
    SecureAllocator(const SecureAllocator<U>&) {}
    template <typename U>
    struct rebind {
        using other = SecureAllocator<U>;
    };
};

template <typename T, typename U>
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
    return true;
}

template <typename T, typename U>
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
    return false;
}

}  // namespace Json
}  // namespace nim_cpp_wrapper_util

#pragma pack(pop)

#endif  // JSON_ALLOCATOR_H_INCLUDED
